from flask import Flask, render_template, request, redirect
from persistence.searchKeyDao import *
import json
import jieba.posseg as pseg
from gevent import monkey
from gevent.pywsgi import WSGIServer
# 猴子补丁如果遇见耗时操作会自动进行协程的切换
monkey.patch_all()

from multiprocessing import cpu_count, Process



app = Flask(__name__)


@app.route('/key/search/', methods=['GET'])
def search():
    id1 = request.args.get('id')
    isVIP = request.args.get('isVIP')
    type1 = request.args.get('type')
    body = request.args.get('body')
    flag = request.args.get('flag')
    page = request.args.get('page')
    print("GET => id = {} isVIP = {} type = {} body = {} flag = {} ".format(id1, isVIP, type1, body, flag))
    word_id = get_word_id(body)

    # print(word_id)
    if type1 == '1':
        # 中介
        mid_word = get_mid_word(word_id)
        words = [word_t1 for word_t1 in mid_word[1].split('|') if word_t1]
        numbers = [word_t2 for word_t2 in mid_word[2].split('|') if word_t2]
        re_mid = []
        for word in words:
            re_mid.append(get_id_to_word(int(word)))
        re_mid, numbers = guolv(re_mid, numbers, flag)

        len_mid = len(re_mid)

        re_mid = re_mid[(int(page) - 1) * 10:int(page) * 10 + 1]
        numbers = numbers[(int(page) - 1) * 10:int(page) * 10 + 1]

        temp_dict = {}
        temp_dict['data'] = {'mid': re_mid, 'metric': numbers, 'len': len_mid}
        return json.dumps(temp_dict)

    if type1 == "2":
        # 竞争
        cpt_words = get_cpt_word(word_id)
        cpt_dict = {}
        cpt_word = cpt_words[int(page) - 1]
        cpt_word1 = [word_t1 for word_t1 in cpt_word[2].split('|') if word_t1]
        cpt_number1 = [word_t2 for word_t2 in cpt_word[3].split('|') if word_t2]
        re_cpt = []
        for word in cpt_word1:
            re_cpt.append(get_id_to_word(int(word)))
        re_cpt, cpt_number1 = guolv(re_cpt, cpt_number1, flag)

        mid_cpt = get_id_to_word(int(cpt_word[1]))
        cpt_temp_dict = {}
        cpt_temp_dict['data'] = {'cpt': re_cpt, 'metric': cpt_number1, 'mid_cpt': mid_cpt, 'len': len(cpt_words) * 10}
        return json.dumps(cpt_temp_dict)

    if type1 == "3":
        # 长尾
        lt_word = get_lt_word(word_id)
        words_lt = [word_t111 for word_t111 in lt_word[1].split('|') if word_t111]
        words_lt = guolv1(words_lt, flag)
        len_lt = len(words_lt)
        words_lt = words_lt[(int(page) - 1) * 10:int(page) * 10 + 1]
        lt_temp_dict = {}
        lt_temp_dict['data'] = {'lt': words_lt, 'len': len_lt}
        return json.dumps(lt_temp_dict)
    return 'get'


def guolv(words, numbers, flag):
    """
        0000 不过滤
        1XXX 过滤单字
        X1XX 过滤数字
        XX1X 过滤动词
        XXX1 过滤名词
    """
    remove_list = set()
    if flag[0] == '1':
        for i, word in enumerate(words):
            if len(word) == 1:
                remove_list.add(i)
    if flag[1] == '1':
        for i, word in enumerate(words):
            if str.isdigit(word):
                remove_list.add(i)
    if flag[2] == '1' or flag[3] == '1':
        for i, word in enumerate(words):
            if not is_contain_chinese(word):
                remove_list.add(i)
    if flag[2] == '1':
        for i, word in enumerate(words):
            for word_n in pseg.cut(word):
                if word_n.flag.startswith('v'):
                    remove_list.add(i)
    if flag[3] == '1':
        for i, word in enumerate(words):
            for word_v in pseg.cut(word):
                if word_v.flag.startswith('n'):
                    remove_list.add(i)
    remove_list = sorted(remove_list, reverse=True)
    for num in remove_list:
        words.pop(num)
        numbers.pop(num)

    return words, numbers


def guolv1(words, flag):
    """
        0000 不过滤
        1XXX 过滤单字
        X1XX 过滤数字
        XX1X 过滤动词
        XXX1 过滤名词
    """
    remove_list = set()
    if flag[0] == '1':
        for i, word in enumerate(words):
            if len(word) == 1:
                remove_list.add(i)
    if flag[1] == '1':
        for i, word in enumerate(words):
            if str.isdigit(word):
                remove_list.add(i)
    if flag[2] == '1' or flag[3] == '1':
        for i, word in enumerate(words):
            if not is_contain_chinese(word):
                remove_list.add(i)
    if flag[2] == '1':
        for i, word in enumerate(words):
            for word_n in pseg.cut(word):
                if word_n.flag.startswith('v'):
                    remove_list.add(i)
    if flag[3] == '1':
        for i, word in enumerate(words):
            for word_v in pseg.cut(word):
                if word_v.flag.startswith('n'):
                    remove_list.add(i)
    remove_list = sorted(remove_list, reverse=True)
    for num in remove_list:
        words.pop(num)
    return words


def is_contain_chinese(check_str):
    """
    判断字符串中是否包含中文
    :param check_str: 需要检测的字符串
    :return: 包含返回True， 不包含返回False
    """
    for ch in check_str:
        if '\u4e00' <= ch <= '\u9fff':
            return True
    return False

def run(MULTI_PROCESS):
    """
    Web Server Gateway Interface，WSGI解构服务器和app，使得代码这边自己可以高并发，这玩意就是个中间件
    WSGI协议主要包括server和application两部分
    server：处理 HTTP 协议，接受用户 HTTP 请求和提供并发，调用 web application 处理业务逻辑
    application：处理server转发的请求

    flask + gevent + multiprocess + wsgi实现高并发(多进程 + 协程)
    原理：
        1. Flask实现的Web框架接口间是非阻塞的，即调用一个接口,不需要等待返回结果；
        2. 对于高并发的任务动辄几十万的数量而言，使用多进程或者多线程无异于找死，很容易造成资源崩溃的情况。所以为了实现并发一般都是采用协程进行并发。
        3. gevent的WSGIServer，自身就实现了协程，基于greenlet和wsgiref两个协程库，因此直接调用即可
    """
    # 不执行多进程
    if MULTI_PROCESS == False:
        # 参数1：server; 参数2：app; WSGIServer：中间件
        WSGIServer(('0.0.0.0', 5000), app).serve_forever()
    # 执行多进程
    else:
        mulserver = WSGIServer(('0.0.0.0', 5000), app)
        mulserver.start()

        def server_forever():
            mulserver.start_accepting()
            mulserver._stop_event.wait()

        # 根据CPU个数，启动进程
        for i in range(cpu_count()):
            p = Process(target=server_forever)
            p.start()


if __name__ == '__main__':
    app.run()
    # 单进程 + 协程
    # run(False)
    # 多进程 + 协程
    run(True)